package com.yb0os1.List;

import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;

public class MyLinkedList<E> implements List<E> {

    private int size;
    private Node<E> tail;//尾节点
    private Node<E> head;//头节点

    @Override//尾插法
    public void add(E element) {
        Node<E> node = new Node<>(tail, element, null);//尾插法
        if (tail != null) tail.next = node;
        else head = node;
        tail = node;
        ++size;
    }

    @Override//对应的下标插入元素
    public void add(E element, int index) {
        //先判断index是否合法
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("index:" + index + "size:" + size);
        }
        //尾插
        if (size == index) {
            add(element);
            return;
        }
        //中间插入 先找到在那个位置插入
        Node<E> indexNode = findNode(index);
        Node<E> newNode = new Node<>(indexNode.prev, element, indexNode);
        if (indexNode.prev == null) {//代表indexNode是头节点
            head = newNode;
        } else {
            indexNode.prev.next = newNode;
        }
        indexNode.prev = newNode;
        ++size;
    }

    //查找一个节点 如果index在左半边就从head遍历 如果index在右半边就从tail遍历
    private Node<E> findNode(int index) {
        Node<E> cur;
        if(index> size/2){
            //从tail开始遍历
            cur = tail;
            while (++index < size) {
                cur = cur.prev;
            }
        }else{
            //从head开始遍历
           cur = head;
            while (index-- > 0) {
                cur = cur.next;
            }
        }
        return cur;
    }

    @Override
    public E remove(int index) {
        //先判断index是否合法
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("index:" + index + "size:" + size);
        }
        //找到要删除的节点
        Node<E> indexNode = findNode(index);
        if (indexNode.prev == null) {//头节点
            head = indexNode.next;
        } else{//非头节点
             indexNode.prev.next = indexNode.next;
        }
        if (indexNode.next == null) {//尾节点
            tail = indexNode.prev;
        } else {//非尾节点
            indexNode.next.prev = indexNode.prev;
        }
        indexNode.next = null;
        indexNode.prev = null;
        --size;
        return indexNode.value;
    }

    @Override
    public boolean remove(E element) {
        Node<E> curNode = head;
        int index = 0;
        while (curNode != null) {
            if (Objects.equals(element, curNode.value)) {
                remove(index);
                return true;
            }
            ++index;
            curNode = curNode.next;
        }
        return false;
    }

    @Override
    public E set(E element, int index) {
        //先判断index是否合法
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("index:" + index + "size:" + size);
        }
        Node<E> indexNode = findNode(index);
        E oldValue = indexNode.value;
        indexNode.value = element;
        return oldValue;
    }

    @Override
    public E get(int index) {
        //先判断index是否合法
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("index:" + index + "size:" + size);
        }
        Node<E> indexNode = findNode(index);
        return indexNode.value;
    }


    @Override
    public int size() {
        return size;
    }


    /**
     * Returns an iterator over elements of type {@code T}.
     *
     * @return an Iterator.
     */
    @Override
    public Iterator<E> iterator() {
        return new LinkedListIterator();
    }

    private class LinkedListIterator implements Iterator<E> {
        Node<E> curNode = head;
        @Override
        public boolean hasNext() {
            return curNode!=null;
        }

        /**
         * Returns the next element in the iteration.
         *
         * @return the next element in the iteration
         * @throws NoSuchElementException if the iteration has no more elements
         */
        @Override
        public E next() {
            if (curNode==null){
                 throw new NoSuchElementException();
            }
            E value = curNode.value;
            curNode = curNode.next;
            return value;
        }
    }

    private class Node<E> {
        E value;
        Node<E> next;//后继
        Node<E> prev;//前驱

        public Node(E value) {
            this.value = value;
        }

        public Node(Node<E> prev, E value, Node<E> next) {
            this.value = value;
            this.next = next;
            this.prev = prev;
        }
    }
}
